package com.view.cn.mvprxjava.utils;

import android.graphics.Point;

import java.util.ArrayList;

/**
 * 五子棋人机算法之 防御型算法
 * Created by Zengxiaoping on 2016/12/16.
 */

public class PieceDefensiveUtils {

	private static final int MAX_LINE_NUMBER = AIUtils.MAX_LINE_NUMBER;      //棋盘最大行列数
	private static final int MAX_NUMBER_IN_LINE = AIUtils.MAX_NUMBER_IN_LINE;//五子连珠游戏结束

	/**
	 * 防御型评分
	 *
	 * @param point         用户落子的点
	 * @param dataListWhite 用户落子点的集合
	 * @param dataListBlack 机器落子的点的集合
	 * @return 返回防御型得分最大的点
	 */
	public static AIUtils.ResultPoint getDefensivePoint(Point point, ArrayList<Point> dataListWhite, ArrayList<Point> dataListBlack) {
		AIUtils.ResultPoint inHorizontalPoint = getInHorizontalPoint(point, dataListWhite, dataListBlack, false);
		AIUtils.ResultPoint inVerticalPoint = getInVerticalPoint(point, dataListWhite, dataListBlack, false);
		AIUtils.ResultPoint inLeftDiagonalPoint = getInLeftDiagonalPoint(point, dataListWhite, dataListBlack, false);
		AIUtils.ResultPoint inRightDiagonalPoint = getInRightDiagonalPoint(point, dataListWhite, dataListBlack, false);

		AIUtils.ResultPoint resultPoint = inHorizontalPoint.scoreNumber > inVerticalPoint.scoreNumber ? inHorizontalPoint : inVerticalPoint;
		resultPoint = resultPoint.scoreNumber > inLeftDiagonalPoint.scoreNumber ? resultPoint : inLeftDiagonalPoint;
		resultPoint = resultPoint.scoreNumber > inRightDiagonalPoint.scoreNumber ? resultPoint : inRightDiagonalPoint;
		return resultPoint;
	}

	/**
	 * 计算水平方向上，机器落子点的得分
	 *
	 * @param isUser 是用户？
	 */
	private static AIUtils.ResultPoint getInHorizontalPoint(Point point, ArrayList<Point> dataListWhite, ArrayList<Point> dataListBlack, boolean isUser) {
		AIUtils.ResultPoint resultPoint = new AIUtils.ResultPoint();
		//下面4个变量用于最后计算落子点分数
		boolean leftExistBlack = false;                                   //左边是否存在堵死的对手棋子,或者处于边界
		boolean rightExistBlack = false;                                  //右边是否存在堵死的对手棋子,或者处于边界
		int leftSumNumber = 0;                                            //落子点左边存在能连成一线棋子的数量
		int rightSumNumber = 0;                                           //落子点右边存在能连成一线棋子的数量

			for (Point pointWhite : dataListWhite) {
				//每次都要重置数据
				leftExistBlack = false;
				rightExistBlack = false;
				leftSumNumber = 0;
				rightSumNumber = 0;
				//定义一个临时存放数据点的得分。用于和最终resultPoint比较，得分更高就替换
				AIUtils.ResultPoint temporaryPoint = new AIUtils.ResultPoint();

				int i = 0;                                                    //
				if (pointWhite.x != 0) {                                               //刚下的棋子在左边边界，跳过左边检测
					int minNumber = Math.min(MAX_NUMBER_IN_LINE - 1, pointWhite.x);
					while (i < minNumber) {       //取小值（4，左边能下的棋子数）；最大值为3,最小为0
						Point point1 = new Point(pointWhite.x - (i + 1), pointWhite.y);
						if (dataListWhite.contains(point1)) {                     //依次往左根据刚下的棋子的X坐标-i，检测是否包涵棋手的棋子
							++leftSumNumber;
							++i;
						} else {
							i = MAX_NUMBER_IN_LINE;                           //i=5，不能满足下一次循环，跳出while循环
							if (dataListBlack.contains(point1)) {                 //检查是否存在对手棋子堵死左边
								leftExistBlack = true;
							} else {
								temporaryPoint.point = point1;                       //如果没被堵死，先存这个点
							}
						}
					}
				} else {
					leftExistBlack = true;
				}
				//重置i=0;
				i = 0;
				if (pointWhite.x != MAX_LINE_NUMBER - 1) {                             //刚下的棋子在右边边界，跳过右边检测
					//i<某值【取小值（4-leftSumNumber，右边能下的棋子数）；最大值为4-leftSumNumber,最小为0】
					int minNumber = Math.min(MAX_NUMBER_IN_LINE - 1 - leftSumNumber, (MAX_LINE_NUMBER - 1) - pointWhite.x);
					while (i < minNumber) {
						Point point1 = new Point(pointWhite.x + (i + 1), pointWhite.y);
						if (dataListWhite.contains(point1)) {                     //依次往左根据刚下的棋子的X坐标-i，检测是否包涵棋手的棋子
							++rightSumNumber;
							++i;
						} else {
							i = MAX_NUMBER_IN_LINE;
							if (dataListBlack.contains(point1)) {
								rightExistBlack = true;
							} else {
								temporaryPoint.point = point1;
							}
						}
					}
				} else {
					rightExistBlack = true;
				}
				if (temporaryPoint.point != null) {                                  //存在能下的点,就去计算得分
					int scoreNumber = AIUtils.ResultPoint.getScoreNumber(leftExistBlack, rightExistBlack, leftSumNumber + rightSumNumber + 1, isUser);
					temporaryPoint.scoreNumber = scoreNumber;
					if (temporaryPoint.scoreNumber > resultPoint.scoreNumber) {      //新计算的出来的点分数更高就最为最终返回的点
						resultPoint = temporaryPoint;
					}
				}
			}
		return resultPoint;
	}

	/**
	 * 计算竖直方向上，机器落子点的得分
	 */
	private static AIUtils.ResultPoint getInVerticalPoint(Point point, ArrayList<Point> dataListWhite, ArrayList<Point> dataListBlack, boolean isUser) {
		AIUtils.ResultPoint resultPoint = new AIUtils.ResultPoint();
		//下面4个变量用于最后计算落子点分数
		boolean topExistBlack = false;                                    //顶部是否存在堵死的对手棋子,或者处于边界
		boolean bottomExistBlack = false;                                 //底部是否存在堵死的对手棋子,或者处于边界
		int topSumNumber = 0;                                             //落子点顶部存在能连成一线棋子的数量
		int bottomSumNumber = 0;                                          //落子点底部存在能连成一线棋子的数量

			for (Point pointWhite : dataListWhite) {
				topExistBlack = false;
				bottomExistBlack = false;
				topSumNumber = 0;
				bottomSumNumber = 0;
				//定义一个临时存放数据点的得分。用于和最终resultPoint比较，得分更高就替换
				AIUtils.ResultPoint temporaryPoint = new AIUtils.ResultPoint();

				int i = 0;
				if (pointWhite.y != 0) {                                               //刚下的棋子在顶部边界，跳过顶部检测
					int minNumber = Math.min(MAX_NUMBER_IN_LINE - 1, pointWhite.y);    //取小值（4，左边能下的棋子数）；最大值为3,最小为0
					while (i < minNumber) {
						Point point1 = new Point(pointWhite.x, (pointWhite.y - (i + 1)));
						if (dataListWhite.contains(point1)) {                     //依次往顶部据刚下的棋子的X坐标-i，检测是否包涵棋手的棋子
							++topSumNumber;
							++i;
						} else {
							i = MAX_NUMBER_IN_LINE;                               //i=5，不能满足下一次循环，跳出while循环
							if (dataListBlack.contains(point1)) {                 //检查是否存在对手棋子堵死顶部
								topExistBlack = true;
							} else {
								temporaryPoint.point = point1;                       //如果没被堵死，先存这个点
							}
						}
					}
				} else {
					topExistBlack = true;
				}
				//重置i=0;
				i = 0;
				if (pointWhite.y != MAX_LINE_NUMBER - 1) {                             //刚下的棋子在底部边界，跳过底部检测
					//i<某值【取小值（4-topSumNumber，右边能下的棋子数）；最大值为4-topSumNumber,最小为0】
					int minNumber = Math.min(MAX_NUMBER_IN_LINE - 1 - topSumNumber, (MAX_LINE_NUMBER - 1) - pointWhite.y);
					while (i < minNumber) {
						Point point1 = new Point(pointWhite.x, (pointWhite.y + (i + 1)));
						if (dataListWhite.contains(point1)) {                     //以此底部根据刚下的棋子的X坐标-i，检测是否包涵棋手的棋子
							++bottomSumNumber;
							++i;
						} else {
								i = MAX_NUMBER_IN_LINE;                               //i=5，不能满足下一次循环
							if (dataListBlack.contains(point1)) {
								bottomExistBlack = true;
							} else {
								temporaryPoint.point = point1;
							}
						}
					}
				} else {
					bottomExistBlack = true;
				}
				if (temporaryPoint.point != null) {                                  //存在能下的点,就去计算得分
					int scoreNumber = AIUtils.ResultPoint.getScoreNumber(topExistBlack, bottomExistBlack, topSumNumber +
							bottomSumNumber + 1, isUser);
					temporaryPoint.scoreNumber = scoreNumber;
					if (temporaryPoint.scoreNumber > resultPoint.scoreNumber) {      //新计算的出来的点分数更高就最为最终返回的点
						resultPoint = temporaryPoint;
					}
				}
			}
		return resultPoint;
	}

	/**
	 * 计算左斜线方向上，机器落子点的得分
	 */
	private static AIUtils.ResultPoint getInLeftDiagonalPoint(Point point, ArrayList<Point> dataListWhite, ArrayList<Point> dataListBlack, boolean isUser) {
		AIUtils.ResultPoint resultPoint = new AIUtils.ResultPoint();
		//下面4个变量用于最后计算落子点分数
		boolean leftDiagonalLeftExistBlack = false;                           //左斜线左边是否存在堵死的对手棋子,或者处于边界
		boolean leftDiagonalRightExistBlack = false;                          //左斜线右边是否存在堵死的对手棋子,或者处于边界
		int leftDiagonalLeftSumNumber = 0;                                    //落子点左斜线左边存在能连成一线棋子的数量
		int leftDiagonalRightSumNumber = 0;                                   //落子点左斜线右边存在能连成一线棋子的数量

			for (Point pointWhite : dataListWhite) {
				leftDiagonalLeftExistBlack = false;
				leftDiagonalRightExistBlack = false;
				leftDiagonalLeftSumNumber = 0;
				leftDiagonalRightSumNumber = 0;
				//定义一个临时存放数据点的得分。用于和最终resultPoint比较，得分更高就替换
				AIUtils.ResultPoint temporaryPoint = new AIUtils.ResultPoint();

				int i = 0;
				if (pointWhite.y != 0) {
					//三个值取最小
					int minNumber = (MAX_NUMBER_IN_LINE - 1) < pointWhite.y ? ((MAX_NUMBER_IN_LINE - 1) < pointWhite.x ?
							(MAX_NUMBER_IN_LINE - 1) : pointWhite.x) : (pointWhite.y < pointWhite.x ? pointWhite.y : pointWhite.x);
					while (i < minNumber) {
						Point point1 = new Point(pointWhite.x - (i + 1), pointWhite.y - (i + 1));
						if (dataListWhite.contains(point1)) {
							++leftDiagonalLeftSumNumber;
							++i;
						} else {
							i = MAX_NUMBER_IN_LINE;                               //i=5，不能满足下一次循环，跳出while循环
							if (dataListBlack.contains(point1)) {
								leftDiagonalLeftExistBlack = true;
							} else {
								temporaryPoint.point = point1;                       //如果没被堵死，先存这个点
							}
						}
					}
				} else {
					leftDiagonalLeftExistBlack = true;
				}
				//重置i=0;
				i = 0;
				if (pointWhite.y != MAX_LINE_NUMBER - 1) {                             //刚下的棋子在底部边界，跳过底部检测
					//同上，三个取最小
					int minNumber = Math.min(MAX_NUMBER_IN_LINE - 1 - leftDiagonalLeftSumNumber, (MAX_LINE_NUMBER - 1) - pointWhite.y);
					minNumber = Math.min(minNumber, (MAX_LINE_NUMBER - 1) - pointWhite.x);
					while (i < minNumber) {
						Point point1 = new Point(pointWhite.x + (i + 1), pointWhite.y + (i + 1));
						if (dataListWhite.contains(point1)) {                     //以此底部根据刚下的棋子的X坐标-i，检测是否包涵棋手的棋子
							++leftDiagonalRightSumNumber;
							++i;
						} else {
							i = MAX_NUMBER_IN_LINE;                               //i=5，不能满足下一次循环
							if (dataListBlack.contains(point1)) {
								leftDiagonalRightExistBlack = true;
							} else {
								temporaryPoint.point = point1;
							}
						}
					}
				} else {
					leftDiagonalRightExistBlack = true;
				}
				if (temporaryPoint.point != null) {                                  //存在能下的点,就去计算得分
					int scoreNumber = AIUtils.ResultPoint.getScoreNumber(leftDiagonalLeftExistBlack, leftDiagonalRightExistBlack, leftDiagonalLeftSumNumber +
							leftDiagonalRightSumNumber + 1, isUser);
					temporaryPoint.scoreNumber = scoreNumber;
					if (temporaryPoint.scoreNumber > resultPoint.scoreNumber) {      //新计算的出来的点分数更高就最为最终返回的点
						resultPoint = temporaryPoint;
					}
				}
			}
		return resultPoint;
	}

	/**
	 * 计算右斜线方向上，机器落子点的得分
	 */
	private static AIUtils.ResultPoint getInRightDiagonalPoint(Point point, ArrayList<Point> dataListWhite, ArrayList<Point> dataListBlack, boolean isUser) {
		AIUtils.ResultPoint resultPoint = new AIUtils.ResultPoint();
		//下面4个变量用于最后计算落子点分数
		boolean rightDiagonalLeftExistBlack = false;                          //右斜线左边是否存在堵死的对手棋子,或者处于边界
		boolean rightDiagonalRightExistBlack = false;                         //右斜线右边是否存在堵死的对手棋子,或者处于边界
		int rightDiagonalLeftSumNumber = 0;                                   //落子点右斜线左边存在能连成一线棋子的数量
		int rightDiagonalRightSumNumber = 0;                                  //落子点右斜线右边存在能连成一线棋子的数量

			for (Point pointWhite : dataListWhite) {
				rightDiagonalLeftExistBlack = false;
				rightDiagonalRightExistBlack = false;
				rightDiagonalLeftSumNumber = 0;
				rightDiagonalRightSumNumber = 0;
				//定义一个临时存放数据点的得分。用于和最终resultPoint比较，得分更高就替换
				AIUtils.ResultPoint temporaryPoint = new AIUtils.ResultPoint();

				int i = 0;
				if (pointWhite.y != 0) {
					//三个值取最小
					int minNumber = Math.min(MAX_NUMBER_IN_LINE - 1, pointWhite.x);
					minNumber = Math.min(minNumber, (MAX_LINE_NUMBER - 1) - pointWhite.y);
					while (i < minNumber) {
						Point point1 = new Point(pointWhite.x - (i + 1), pointWhite.y + (i + 1));
						if (dataListWhite.contains(point1)) {
							++rightDiagonalLeftSumNumber;
							++i;
						} else {
							i = MAX_NUMBER_IN_LINE;                               //i=5，不能满足下一次循环，跳出while循环
							if (dataListBlack.contains(point1)) {
								rightDiagonalLeftExistBlack = true;
							} else {
								temporaryPoint.point = point1;                       //如果没被堵死，先存这个点
							}
						}
					}
				} else {
					rightDiagonalLeftExistBlack = true;
				}
				//重置i=0;
				i = 0;
				if (pointWhite.y != MAX_LINE_NUMBER - 1) {                             //刚下的棋子在底部边界，跳过底部检测
					//同上，三个取最小
					int minNumber = Math.min(MAX_NUMBER_IN_LINE - 1 - rightDiagonalLeftSumNumber, pointWhite.y);
					minNumber = Math.min(minNumber, (MAX_LINE_NUMBER - 1) - pointWhite.x);
					while (i < minNumber) {
						Point point1 = new Point(pointWhite.x + (i + 1), pointWhite.y - (i + 1));
						if (dataListWhite.contains(point1)) {                     //以此底部根据刚下的棋子的X坐标-i，检测是否包涵棋手的棋子
							++rightDiagonalRightSumNumber;
							++i;
						} else {
							i = MAX_NUMBER_IN_LINE;                               //i=5，不能满足下一次循环
							if (dataListBlack.contains(point1)) {
								rightDiagonalRightExistBlack = true;
							} else {
								temporaryPoint.point = point1;
							}
						}
					}
				} else {
					rightDiagonalRightExistBlack = true;
				}
				if (temporaryPoint.point != null) {                                  //存在能下的点,就去计算得分
					int scoreNumber = AIUtils.ResultPoint.getScoreNumber(rightDiagonalLeftExistBlack, rightDiagonalRightExistBlack,
							rightDiagonalLeftSumNumber + rightDiagonalRightSumNumber + 1, isUser);
					temporaryPoint.scoreNumber = scoreNumber;
					if (temporaryPoint.scoreNumber > resultPoint.scoreNumber) {      //新计算的出来的点分数更高就最为最终返回的点
						resultPoint = temporaryPoint;
					}
				}
			}
		return resultPoint;
	}
}
